// TestHTML.cpp : Defines the entry point for the DLL.
// (C) 2016 Dacris Software Inc.
//

#include "stdafx.h"
#include <windows.h>
#include <malloc.h>
#include "webform.h"
#include "BmarkPlugins.h"

#define TEST_TITLE_STR	"HTML Rendering"
#define TEST_UNIT_STR	"PPM"
#define BUF_SIZE		512
#define UPDATE_FREQ		250
#define SLEEP_MIN		0

extern "C" {
	char cDriveLetter;
	char* lpszHTML;
	BmarkApp* pBmarkApp;
	PluginData pluginData;
	PluginData progressData;
	BmarkNav navData;
	BmarkResult bmarkResult;
	HWND hMainWnd;
	HWND hWebWnd;

	HANDLE hThread;
	DWORD testThreadID;
	BOOL bThreadCancel;

	// returns number of pages rendered
	int HTMLTest()
	{
		WebformReady(hWebWnd);

		lpszHTML = (char*)malloc(BUF_SIZE);
		ZeroMemory(lpszHTML, BUF_SIZE);
		lstrcpy(lpszHTML, "<html><head><title>Render Test</title></head><body>");
		lstrcat(lpszHTML, "<h1>Heading 1</h1>");
		lstrcat(lpszHTML, "<h2>Heading 2. Table</h2>");
		lstrcat(lpszHTML, "<table><tr><td>Col 1</td><td>Col 2</td></tr><tr><td>Col 1</td><td>Col 2</td></tr></table>");
		lstrcat(lpszHTML, "<div><h2>Heading 2. List</h2></div>");
		lstrcat(lpszHTML, "<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>");
		lstrcat(lpszHTML, "<!-- Comment -->");
		lstrcat(lpszHTML, "<h2>Heading 2. Form</h2>");
		lstrcat(lpszHTML, "<form method=\"POST\"><input type=\"text\"></input><input type=\"submit\"></input></form>");
		lstrcat(lpszHTML, "</body></html>");
		WebformSet(hWebWnd, lpszHTML);
		free(lpszHTML);

		WebformGo(hWebWnd, 0);

		Sleep(SLEEP_MIN);

		UpdateWindow(hWebWnd);
		UpdateWindow(hMainWnd);

		return 1;
	}

	//-----------------------------------------------------------------------------
	// Name: MainWndProc()
	// Desc: The main window procedure
	//-----------------------------------------------------------------------------
	LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
	{
		switch (msg)
		{
			case WM_KEYDOWN:
				if (wParam == VK_ESCAPE)
				{
					bThreadCancel = TRUE;
					pBmarkApp->isTestRunning = FALSE;
					pluginData.iValue = BMARK_HIDE_PROGRESS;
					pluginData.pValue = NULL;
					AppMessage(&(pBmarkApp->appData), &pluginData);
				}
				return 0L;

			case WM_CREATE:
				/* Create the browser control */
				hWebWnd = CreateWindow(
					WEBFORM_CLASS,
					_T("about:blank"),
					WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE|WS_VSCROLL,
					0,0,480,360,hWnd,(HMENU)103,GetModuleHandle(0),0);
				break;

			case WM_SIZE:
				MoveWindow(hWebWnd,0,0,LOWORD(lParam),HIWORD(lParam),TRUE);
				break;

			case WM_SYSCOMMAND:
				// Prevent moving/sizing and power loss in fullscreen mode
				switch( wParam )
				{
					case SC_MOVE:
					case SC_SIZE:
					case SC_MAXIMIZE:
					case SC_MONITORPOWER:
						return TRUE;
				}
				break;
	            
			case WM_DESTROY:
				// Cleanup and close the app
				DestroyWindow(hWebWnd);
				return 0L;
		}

		return DefWindowProc(hWnd, msg, wParam, lParam);
	}

	HRESULT RegisterWindowClass()
	{
		WNDCLASS wc;

		// Register the Window Class
		wc.lpszClassName = TEXT("HTMLRendering");
		wc.lpfnWndProc   = MainWndProc;
		wc.style         = CS_VREDRAW | CS_HREDRAW;
		wc.hInstance     = GetModuleHandle("TestHTML.dll");
		wc.hIcon         = NULL;
		wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
		wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
		wc.lpszMenuName  = NULL;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;

		if( RegisterClass( &wc ) == 0 )
		{
			char errorMessage[200];
			wsprintf(errorMessage, "Could not register window class: %d", GetLastError());
			OutputDebugString(errorMessage);
			OutputDebugString("\n");
			return E_FAIL;
		}
		return S_OK;
	}

	BOOL UnregisterWindowClass()
	{
		return UnregisterClass(TEXT("HTMLRendering"),
			GetModuleHandle("TestHTML.dll"));
	}

	//-----------------------------------------------------------------------------
	// Name: WinInit()
	// Desc: Init the window
	//-----------------------------------------------------------------------------
	HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd )
	{
		HWND     hWnd;

		// Create and show the main window
		hWnd = CreateWindowEx( 0, TEXT("HTMLRendering"), TEXT("HTML Rendering Test"),
							   WS_CAPTION|WS_POPUP|WS_CLIPCHILDREN,
							   CW_USEDEFAULT, CW_USEDEFAULT,
  							   512, 384, NULL, NULL, hInst, NULL );
		if( hWnd == NULL )
    		return E_FAIL;

		ShowWindow( hWnd, nCmdShow );
		UpdateWindow( hWnd );

		*phWnd = hWnd;

		return S_OK;
	}

	DWORD WINAPI TestThread(LPVOID lpThreadParameter)
	{
		PluginData *app = (PluginData*)lpThreadParameter;
		DWORD lastUpdate = 0;
		DWORD totalPages = 0;
		DWORD totalDuration = pBmarkApp->settings.iTestDuration
			* pBmarkApp->settings.iNumPasses
			* 1000;
		if (OleInitialize(NULL) != ERROR_SUCCESS)
		{
			OutputDebugString("OLE/COM initialization failed.");
			return 1;
		}
		if( FAILED( WinInit( GetModuleHandle("TestHTML.dll"), SW_SHOWNORMAL, &hMainWnd ) ) )
			return FALSE;
		pBmarkApp->isTestRunning = TRUE;
		DWORD startTicks = GetTickCount();
		DWORD currentTicks = startTicks;
		while( !bThreadCancel && currentTicks - startTicks < totalDuration )
		{
		    MSG  msg = {0};   /* message */
			// Look for messages, if none are found then 
			// update the state and display it
			if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
			{
				if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
				{
					pBmarkApp->isTestRunning = FALSE;
					// WM_QUIT was posted, so exit
					OleUninitialize();
					ExitThread(0);
					return 0;
				}

				// Translate and dispatch the message
				TranslateMessage( &msg ); 
				DispatchMessage( &msg );
			}

			totalPages += HTMLTest();
			currentTicks = GetTickCount();

			if ((currentTicks - startTicks) / UPDATE_FREQ != lastUpdate)
			{
				if (bThreadCancel)
				{
					OleUninitialize();
					pBmarkApp->isTestRunning = FALSE;
					ExitThread(1);
					return 1;
				}
				lastUpdate = (currentTicks - startTicks) / UPDATE_FREQ;
				progressData.iValue = (100 * (currentTicks - startTicks)) / totalDuration;
				progressData.pValue = NULL;

				pluginData.iValue = BMARK_SET_PROGRESS;
				pluginData.pValue = &progressData;
				AppMessage(app, &pluginData);
			}
		}
		pBmarkApp->isTestRunning = FALSE;

		if (!bThreadCancel)
		{
			DWORD result = totalPages * 60 / ((currentTicks - startTicks) / 1000);

			pluginData.iValue = BMARK_HIDE_PROGRESS;
			pluginData.pValue = NULL;
			AppMessage(app, &pluginData);

			bmarkResult.result = result;

			pluginData.iValue = BMARK_SET_RESULT;
			pluginData.pValue = &bmarkResult;
			AppMessage(app, &pluginData);
		}

		OleUninitialize();
		ExitThread(0);
		return 0;
	}

	void __declspec(dllexport) DllPluginFunction(int ordinal, PluginData *app)
	{
		if (ordinal == BMARK_ATTACH)
		{
			lpszHTML = NULL;

			navData.cbTitle = lstrlen(TEST_TITLE_STR) + 1;
			navData.iOrdinal = 0;
			lstrcpy(navData.lpszTitle, TEST_TITLE_STR);

			pluginData.iValue = BMARK_REG_NAV;
			pluginData.pValue = &navData;
			
			AppMessage(app, &pluginData);

			lstrcpy(bmarkResult.unit, TEST_UNIT_STR);
			lstrcpy(bmarkResult.title, TEST_TITLE_STR);

			pluginData.iValue = BMARK_REG_RESULT;
			pluginData.pValue = &bmarkResult;

			AppMessage(app, &pluginData);
		}
		if (ordinal == BMARK_SETUP)
		{
			pBmarkApp = (BmarkApp*)(app->pValue);
			hThread = NULL;
			RegisterWindowClass();
		}
		if (ordinal == BMARK_EXEC)
		{
			pluginData.iValue = BMARK_SHOW_PROGRESS;
			pluginData.pValue = NULL;
			AppMessage(app, &pluginData);

			bThreadCancel = FALSE;
			if (hThread)
			{
				CloseHandle(hThread);
			}
			hThread = CreateThread(NULL, 0, TestThread, app, 0, &testThreadID);
		}
		if (ordinal == BMARK_CANCEL_TEST)
		{
			bThreadCancel = TRUE;
		}
		if (ordinal == BMARK_EXIT)
		{
			pBmarkApp = (BmarkApp*)(app->pValue);
			UnregisterWindowClass();
			if (hThread)
			{
				CloseHandle(hThread);
			}
		}
	}
};